package com.tuzhi.base.jpa.healper;

/**
 * 功能说明：
 *
 * @author abu
 * @version 1.1.0
 * @date 2023/3/13
 */

import com.tuzhi.base.function.SFunction;
import com.tuzhi.base.jpa.domain.QueryConditionBO;
import com.tuzhi.base.jpa.domain.SortConditionBO;
import com.tuzhi.base.jpa.domain.WhereConditionBO;
import com.tuzhi.base.jpa.enums.AndOrOperate;
import com.tuzhi.base.jpa.enums.QueryTypeEnum;
import com.tuzhi.base.jpa.enums.SortOrderEnum;
import com.tuzhi.base.util.PropertyUtil;
import lombok.Getter;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 行高列宽信息（链式Builder模式）
 *
 * @author xudongmaster
 */
@Getter
public class QueryHelper<T> {
    private WhereConditionBO whereConditionBO = null;


    public WhereConditionBO getWhereConditionBO() {
        return whereConditionBO;
    }

    private QueryHelper(Builder builder) {
        this.whereConditionBO = builder.whereConditionBO;
    }

    public void show() {
        StringBuilder sb = new StringBuilder();
        if (whereConditionBO != null) {
            List<SortConditionBO> sortConditionBOList = whereConditionBO.getSortList();
            sb.append("SortCondition:");
            sb.append("\r\n");
            sortConditionBOList.forEach(item -> {
                sb.append(String.format("----propertyName:%s,SortOrder:%s", item.getPropertyName(), item.getSortOrderEnum().toString()));
                sb.append("\r\n");
            });
            sb.append("QueryCondition:");
            sb.append("\r\n");
            List<QueryConditionBO> queryList = whereConditionBO.getQueryList();
            queryList.forEach(item -> {
                sb.append(String.format("----propertyName:%s,type:%s,value:%s", item.getPropertyName(), item.getQueryTypeEnum().toString(), item.getObjValue()));
                sb.append("\r\n");
            });
        }
        System.out.println(sb.toString());
    }


    public static class Builder<T> {
        private WhereConditionBO whereConditionBO = null;

        void WhereConditionBOInit() {
            whereConditionBO = new WhereConditionBO();
            whereConditionBO.setQueryList(new ArrayList<>());
            whereConditionBO.setSortList(new ArrayList<>());
        }

        public Builder() {
            WhereConditionBOInit();
        }

        public QueryHelper build() {
            return new QueryHelper(this);
        }

        public Builder<T> nlk(SFunction<? super T, ?> propertyName, Object filterValue, boolean trueAddFilter) {
            if (trueAddFilter) {
                addQueryFilter(propertyName, AndOrOperate.and, filterValue, QueryTypeEnum.notLike);

            }
            return this;
        }

        /**
         * 指定属性名与属性值作and的nlike查询
         *
         * @param propertyName
         * @param filterValue
         * @return
         */
        public Builder<T> nlk(SFunction<? super T, ?> propertyName, Object filterValue) {
            return nlk(propertyName, filterValue, true);
        }

        /**
         * 指定属性名与属性值作and的nlike查询
         *
         * @param propertyName
         * @param filterValue
         * @return
         */
        public Builder<T> lk(SFunction<? super T, ?> propertyName, Object filterValue, boolean trueAddFilter) {
            if (trueAddFilter) {
                addQueryFilter(propertyName, AndOrOperate.and, filterValue, QueryTypeEnum.like);
            }
            return this;
        }

        /**
         * 指定属性名与属性值作and的nlike查询
         *
         * @param propertyName
         * @param filterValue
         * @return
         */
        public Builder<T> lk(SFunction<? super T, ?> propertyName, Object filterValue, boolean trueAddFilter, AndOrOperate orOperate) {
            if (trueAddFilter) {
                addQueryFilter(propertyName, orOperate, filterValue, QueryTypeEnum.like);
            }
            return this;
        }

        /**
         * 指定属性名与属性值作and的nlike查询
         *
         * @param propertyName
         * @param filterValue
         * @return
         */
        public Builder<T> lk(SFunction<? super T, ?> propertyName, Object filterValue) {
            return lk(propertyName, filterValue, true);

        }


        private void addQueryFilter(SFunction<? super T, ?> propertyName, AndOrOperate andOrOperate, Object filterValue, QueryTypeEnum queryType) {
            QueryConditionBO queryConditionBO = new QueryConditionBO();
            if (andOrOperate == null) {
                andOrOperate = AndOrOperate.and;
            }
            String propertyNameStr = PropertyUtil.getFieldName(propertyName);
            queryConditionBO.setPropertyName(propertyNameStr);
            queryConditionBO.setAndOrOperate(andOrOperate);
            switch (queryType) {
                case in:
                case notIn:
                case between:
                    queryConditionBO.setObjList((List) filterValue);
                    break;
                case isEmpty:
                case isNotEmpty:
                    break;
                default:
                    queryConditionBO.setObjValue(filterValue);
                    break;
            }
            queryConditionBO.setQueryTypeEnum(queryType);
            whereConditionBO.getQueryList().add(queryConditionBO);
        }

        private void addSort(SFunction<? super T, ?> propertyName, SortOrderEnum sortOrderEnum) {
            SortConditionBO sortConditionBO = new SortConditionBO();
            String propertyNameStr = PropertyUtil.getFieldName(propertyName);
            sortConditionBO.setPropertyName(propertyNameStr);
            sortConditionBO.setSortOrderEnum(sortOrderEnum);
            whereConditionBO.getSortList().add(sortConditionBO);
        }

        public Builder<T> sortDesc(SFunction<? super T, ?> propertyName) {
            addSort(propertyName, SortOrderEnum.DESC);
            return this;
        }

        public Builder<T> sortAce(SFunction<? super T, ?> propertyName) {
            addSort(propertyName, SortOrderEnum.ACE);
            return this;
        }

        /**
         * 指定属性名与属性值作and的eq查询
         *
         * @param propertyName
         * @param filterValue
         * @return
         */
        public Builder<T> eq(SFunction<? super T, ?> propertyName, Object filterValue, boolean trueAddFilter) {
            if (trueAddFilter) {
                addQueryFilter(propertyName, AndOrOperate.and, filterValue, QueryTypeEnum.equal);
            }

            return this;
        }

        public Builder<T> eq(SFunction<? super T, ?> propertyName, Object filterValue) {
            return eq(propertyName, filterValue, true);
        }

        public Builder<T> neq(SFunction<? super T, ?> propertyName, Object filterValue, boolean trueAddFilter) {
            if (trueAddFilter) {
                neq(propertyName, filterValue, AndOrOperate.and);
            }
            return this;
        }

        /**
         * 指定属性名与属性值作and neq查询
         *
         * @param propertyName
         * @param filterValue
         * @return
         */
        public Builder<T> neq(SFunction<? super T, ?> propertyName, Object filterValue) {
            return neq(propertyName, filterValue, true);
        }

        /**
         * 指定属性名与属性值作  neq查询
         *
         * @param propertyName
         * @param filterValue
         * @return
         */
        public Builder<T> neq(SFunction<? super T, ?> propertyName, Object filterValue, AndOrOperate andOrOperate) {
            addQueryFilter(propertyName, andOrOperate, filterValue, QueryTypeEnum.notEqual);
            return this;
        }

        /**
         * 对指定的属性，作日期范围查询
         *
         * @param propertyName 属性名
         * @param beginDate    开始日期
         * @param endDate      结束日期
         * @return
         */
        public Builder<T> bwn(SFunction<? super T, ?> propertyName, Date beginDate, Date endDate, AndOrOperate andOrOperate) {
            List<Date> bwnDates = new ArrayList<>();
            bwnDates.add(beginDate);
            bwnDates.add(endDate);
            andOrOperate = andOrOperate != null ? andOrOperate : AndOrOperate.and;
            addQueryFilter(propertyName, andOrOperate, bwnDates, QueryTypeEnum.between);
            return this;
        }

        /**
         * 指定属性名，属性值集合，作in 查找记录
         *
         * @param propertyName
         * @param value
         * @param andOrOperate
         * @return
         */
        public <E> Builder<T> in(SFunction<? super T, ?> propertyName, List<E> value, AndOrOperate andOrOperate) {
            andOrOperate = andOrOperate != null ? andOrOperate : AndOrOperate.and;
            addQueryFilter(propertyName, andOrOperate, value, QueryTypeEnum.in);
            return this;
        }

        public <E> Builder<T> in(SFunction<? super T, ?> propertyName, List<E> value) {
            return in(propertyName, value, AndOrOperate.and);
        }

        /**
         * 大于 >
         *
         * @param propertyName
         * @param filterValue
         * @return
         */
        public Builder<T> gt(SFunction<? super T, ?> propertyName, Object filterValue) {
            addQueryFilter(propertyName, AndOrOperate.and, filterValue, QueryTypeEnum.gt);
            return this;
        }

        /**
         * 小于 <
         *
         * @param propertyName
         * @param filterValue
         * @return
         */
        public Builder<T> lt(SFunction<? super T, ?> propertyName, Object filterValue) {
            addQueryFilter(propertyName, AndOrOperate.and, filterValue, QueryTypeEnum.lt);
            return this;
        }

        /**
         * 大于等于 >=
         *
         * @param propertyName
         * @param filterValue
         * @return
         */
        public Builder<T> gte(SFunction<? super T, ?> propertyName, Object filterValue) {
            addQueryFilter(propertyName, AndOrOperate.and, filterValue, QueryTypeEnum.gt);
            return this;
        }

        /**
         * 小于等于<=
         *
         * @param propertyName
         * @param filterValue
         * @return
         */
        public Builder<T> lte(SFunction<? super T, ?> propertyName, Object filterValue) {
            addQueryFilter(propertyName, AndOrOperate.and, filterValue, QueryTypeEnum.le);
            return this;
        }

        public Builder<T> isEmpty(SFunction<? super T, ?> propertyName ) {
            addQueryFilter(propertyName, AndOrOperate.and, null, QueryTypeEnum.isEmpty);
            return this;
        }

        public Builder<T> isNotEmpty(SFunction<? super T, ?> propertyName ) {
            addQueryFilter(propertyName, AndOrOperate.and, null, QueryTypeEnum.isNotEmpty);
            return this;
        }
        public Builder<T> isNull(SFunction<? super T, ?> propertyName ) {
            addQueryFilter(propertyName, AndOrOperate.and, null, QueryTypeEnum.isNull);
            return this;
        }

        public Builder<T> isNotNull(SFunction<? super T, ?> propertyName ) {
            addQueryFilter(propertyName, AndOrOperate.and, null, QueryTypeEnum.isNotNull);
            return this;
        }

    }

    public static void main(String[] args) {

       /* Builder<ProgramHeaderEntity> builder = new Builder();
        builder.lk(ProgramHeaderEntity::getPlateNo, "3").nlk(ProgramHeaderEntity::getPlateName, "A板").sortAce(ProgramHeaderEntity::getId).build().show();


        System.out.println("======================================================================================");

        Builder<ProgramHeaderEntity> builder1 = new Builder();
        builder1.lk(ProgramHeaderEntity::getPlateNo, "2").nlk(ProgramHeaderEntity::getPlateName, "B板").build().show();

*/

    }


}
